#include "StdAfx.h"
#include "Frame.hxx"

#include "ProcessStream.hxx"

#include "FrameUndistortStep.hxx"

#include "FrameArray.hxx"
#include "YUVFrameConverter.hxx"

#include "StreamSynchronizer.hxx"
#include "ForegroundDetectionStep.hxx"
#include "PipeLine.hxx"

#include "TrackerModel.hxx"
#include "ChannelModel.hxx"

#include <opencv\cv.h>
#include <opencv\highgui.h>


ProcessStream::ProcessStream(void)
{
	_frameArray = 0;
	_nextFrameIndex = 0;
	_pipeLine = 0;
	_streamId = 0;
	_isStopped = true;

	_hStreamThread = 0;

	for( int i = 0; i < PROCESS_STEP_COUNT; i ++ )
		_steps[ i ] = 0;
}


ProcessStream::~ProcessStream(void)
{
	release();
}

void ProcessStream::initialize()
{
	_frameArray = new FrameArray();
	_frameArray->setPageCount( 50 );
	_frameArray->setPageSize( sizeof( Frame ) );
	_frameArray->initialize();
	
	_steps[ 0 ] = new FrameUndistortStep( this );
	_steps[ 0 ]->initialize();

	_steps[ 1 ] = new ForegroundDetectionStep( this );
	_steps[ 1 ]->initialize();

	_frameConverter = new YUVFrameConverter();
	_frameConverter->setFrameWidth( RAW_FRAME_WIDTH );
	_frameConverter->setFrameHeight( RAW_FRAME_HEIGHT );
	_frameConverter->initialize();

}

void ProcessStream::release()
{
	if( _isStopped )
		stop();

	for( int i = 0; i < PROCESS_STEP_COUNT; i ++ )
	{
		if( _steps[ i ] )
			delete _steps[ i ];
		_steps[ i ] = 0;
	}

	if( _frameArray )
	{
		delete _frameArray;
		_frameArray = 0;
	}
}

IplImage* YUV2IplImage( const char* buffer, const int w, const int h )
{
	IplImage *py, *pu, *pv, *pu_big, *pv_big, *image;
	
	py = cvCreateImage(cvSize(w,h), IPL_DEPTH_8U, 1);
	pu = cvCreateImage(cvSize(w/2,h/2), IPL_DEPTH_8U, 1);
	pv = cvCreateImage(cvSize(w/2,h/2), IPL_DEPTH_8U, 1);

    pu_big = cvCreateImage(cvSize(w,h), IPL_DEPTH_8U, 1);
    pv_big = cvCreateImage(cvSize(w,h), IPL_DEPTH_8U, 1);

    image = cvCreateImage(cvSize(w,h), IPL_DEPTH_8U, 3);
	
	int offset = 0;
	int tsize = w * h;
	
	memcpy( py->imageData , buffer + offset, tsize );
	
	offset += tsize;
	memcpy( pu->imageData , buffer + offset, tsize / 4 );
	
	offset += tsize / 4;
	memcpy( pv->imageData , buffer + offset, tsize / 4 );
	
	cvResize(pu, pu_big, CV_INTER_LINEAR);
	cvResize(pv, pv_big, CV_INTER_LINEAR);
	
	cvReleaseImage(&pu);
	cvReleaseImage(&pv);
	
	cvMerge(py, pu_big,pv_big, NULL, image);
	
	cvCvtColor(image,image,CV_YCrCb2RGB);

    cvReleaseImage(&py);
    cvReleaseImage(&pu_big);
    cvReleaseImage(&pv_big);

    return image;
}


void ProcessStream::addFrame(  char* raw )
{
	//printf("%d:%d\n",_streamId, _nextFrameIndex++ );
	Block bx;

	int tidx = -1;

	Frame* frame = (Frame*)(_frameArray->getNextFreeFrame( tidx )); 

	char fname[ 64 ];
	sprintf( fname, "d:/Temp/RGB_CH%d_%06d.png", _streamId, _nextFrameIndex );

	_frameConverter->convert( raw, fname );
	
	StreamSynchronizer* synchronizer = _pipeLine->getStreamSynchronizer();

	if( frame )
	{
		frame->FrameIndex = _nextFrameIndex ++ ;
		frame->StoreIndex = tidx;
		frame->ProcessStepFlag = STEP_FRAME_UNDISTORT;
		frame->TrackingBlock = bx;
		frame->ForegroundBlock = bx;

		_frameConverter->copyImageData( frame->FrameImage );
		
		//ChannelModel* model = _pipeLine->getTrackerModel()->getSubModel( _streamId );
		//if( model ) model->updateImageData( frame->FrameImage );

		_frameArray->useFrame( tidx , frame->FrameIndex );

		synchronizer->synchronizeFrame( _streamId,frame );

	}
	else
	{
		printf("<<<<<<<<<<<<<[%d : %d] Lost a frame!!\n", _streamId,_nextFrameIndex);
		_nextFrameIndex ++;
	}
}


DWORD WINAPI StreamProc(LPVOID lpParam)
{
	ProcessStream* stream = (ProcessStream*)lpParam;

	FrameArray* frameArray = stream->getFrameArray();

	while( !stream->isStopped() )
	{
		if( frameArray->isEmpty() )
			Sleep( 10 );
		else
		{
			stream->execute();
		}
	}
	return 0;
}

void ProcessStream::start()
{
	_isStopped = false;

	DWORD dwThreadID = 0;
	
	_hStreamThread = CreateThread( NULL, 0, StreamProc, this, 0, &dwThreadID );

}

void ProcessStream::execute()
{
	for( int i = 0; i < PROCESS_STEP_COUNT; i ++ )
	{
		if( _steps[ i ] )
			_steps[ i ]->execute();
	}
}

void ProcessStream::stop()
{
	BOOL bRet = TRUE;

	_isStopped = true;
	
	WaitForSingleObject( _hStreamThread, INFINITE);
	
	bRet = CloseHandle( _hStreamThread );
	
	if ( bRet == TRUE )
	{
            _hStreamThread = NULL;
	}
	else
	{
		printf("Close Stream Thread fail!\n");
	}
}
